home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume20 / opcom < prev    next >
Encoding:
Internet Message Format  |  1989-10-22  |  26.4 KB

  1. Subject:  v20i049:  Operator interface with limited privileges
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Carel Braam <mcvax!eutrc3!rccarel>
  7. Posting-number: Volume 20, Issue 49
  8. Archive-name: opcom
  9.  
  10. Opcom is a program, that enables users, belonging to a special group to
  11. execute a limited set of commands with another userid or groupid.
  12. This makes it possible to perform daily system administration tasks without
  13. having the full privileges of root.
  14.  
  15. Carel Braam
  16.  
  17. uucp:    rccarel@eutrc3.UUCP    | Computing Centre
  18. bitnet: rccarel@heithe5.BITNET    | Eindhoven University of Technology
  19. phone: 040-472158        | Den Dolech 2, P.O. Box 513
  20. home:  040-810381        | 5600 MB Eindhoven, The Netherlands
  21.  
  22. ---
  23.  
  24. #! /bin/sh
  25. # This is a shell archive.  Remove anything before this line, then unpack
  26. # it by saving it into a file and typing "sh file".  To overwrite existing
  27. # files, type "sh file -c".  You can also feed this as standard input via
  28. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  29. # will see the following message at the end:
  30. #        "End of archive 1 (of 1)."
  31. # Contents:  README bsd.make config detab.c opcom.c srctoman sysdep
  32. #   sysv.make
  33. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  34. if test -f README -a "${1}" != "-c" ; then 
  35.   echo shar: Will not over-write existing file \"README\"
  36. else
  37. echo shar: Extracting \"README\" \(1537 characters\)
  38. sed "s/^X//" >README <<'END_OF_README'
  39. XOpcom is a program, that enables users, belonging to a special group to
  40. Xexecute a limited set of commands with another userid or groupid.
  41. XThis makes it possible to perform daily system administration tasks without
  42. Xhaving the full privileges of root.
  43. X
  44. X
  45. XCarel Braam
  46. X
  47. Xuucp:    rccarel@eutrc3.UUCP    | Computing Centre
  48. Xbitnet: rccarel@heithe5.BITNET    | Eindhoven University of Technology
  49. Xphone: 040-472158        | Den Dolech 2, P.O. Box 513
  50. Xhome:  040-810381        | 5600 MB Eindhoven, The Netherlands
  51. X
  52. X
  53. X                INSTALLATION NOTES
  54. X                ==================
  55. X
  56. XBefore you start off adapt the file config to your local needs.
  57. XAll system dependent variables are set between the comment
  58. X
  59. X#    *** System dependent variables ***
  60. X
  61. Xand  the comment
  62. X
  63. X#    *** End system dependent variables ***
  64. X
  65. XCurrently the following variables can be set:
  66. X
  67. XOPCOMDIR    The directory for the files COMMANDS and PROFILE.
  68. XCOMMANDS    The file containing the commands, that are allowed.
  69. XPROFILE        The file containing the profile to be executed.
  70. X
  71. XAs well the manual page opcom.8 as sysdep.h are dependent on config.
  72. XTo make opcom use the makefile bsd.make, if you have a bsd system, or
  73. Xsysv.make, if you have system V.
  74. XYou can create the manual page by entering make man.
  75. XThen as super user type make install to install opcom and make installman
  76. Xto install the manual page.
  77. XSee the makefile for the definition of the local bin directory and the local
  78. Xmanual directory.
  79. X
  80. X#++
  81. X# CREATION DATE
  82. X#    Thu Jan  5 11:25:04 MET 1989
  83. X# LAST MODIFICATION
  84. X#    Tue Jan 17 13:15:36 MET 1989
  85. X# VERSION/RELEASE
  86. X#    1.3
  87. X#--
  88. END_OF_README
  89. if test 1537 -ne `wc -c <README`; then
  90.     echo shar: \"README\" unpacked with wrong size!
  91. fi
  92. # end of overwriting check
  93. fi
  94. if test -f bsd.make -a "${1}" != "-c" ; then 
  95.   echo shar: Will not over-write existing file \"bsd.make\"
  96. else
  97. echo shar: Extracting \"bsd.make\" \(1915 characters\)
  98. sed "s/^X//" >bsd.make <<'END_OF_bsd.make'
  99. X#++
  100. X# NAME
  101. X#    bsd.make 
  102. X# SUMMARY
  103. X#    makefile for opcom.
  104. X# AUTHOR(S)
  105. X#
  106. X#      C.G.S.M. Braam
  107. X#      Eindhoven University of Technology
  108. X#      Computing Centre
  109. X#      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  110. X# CREATION DATE
  111. X#    Thu Jan  5 10:41:57 MET 1989
  112. X# LAST MODIFICATION
  113. X#    Tue Jan 17 13:15:23 MET 1989
  114. X# VERSION/RELEASE
  115. X#    1.3
  116. X#--
  117. X
  118. X# System dependent variables
  119. X
  120. XCC = cc
  121. XCDEFS = -DBSD
  122. XCFLAGS = -O
  123. XLFLAGS = -h
  124. XBINDIR = /usr/local/bin
  125. XMANDIR = /usr/local/man
  126. X
  127. X# End system dependent variables
  128. X
  129. XCSOURCES = opcom.c
  130. XHFILES = sysdep
  131. XSHELLS = config
  132. XMAKEFILES = bsd.make sysv.make
  133. XOPSOURCES = $(CSOURCES) $(HFILES) $(SHELLS) $(MAKEFILES) README
  134. XUSOURCES = detab.c srctoman
  135. XSOURCES = $(OPSOURCES) $(USOURCES)
  136. X
  137. Xall:    opcom
  138. X
  139. Xsysdep.h: sysdep config
  140. X    sh config sysdep >sysdep.h
  141. X
  142. Xman:    opcom.8
  143. X
  144. Xopcom.8: opcom.c config detab
  145. X    sh srctoman -L opcom.c | sh config >opcom.8
  146. X
  147. X# Lint.
  148. X
  149. Xlint:    sysdep.h
  150. X    lint $(LFLAGS) $(CDEFS) opcom.c
  151. X
  152. X
  153. Xdetab: detab.c
  154. X    $(CC) $(CFLAGS) $(CDEFS) detab.c -o detab
  155. X
  156. Xopcom: opcom.c sysdep.h
  157. X    $(CC) $(CFLAGS) $(CDEFS) opcom.c -o opcom
  158. X
  159. X# Installation and update.
  160. X
  161. Xinstall: opcom
  162. X    cp opcom $(BINDIR)
  163. X    cd $(BINDIR); chown root opcom; chmod u+s opcom
  164. X
  165. Xinstallman: man
  166. X     cp opcom.8 $(MANDIR)/man8
  167. X     rm -f $(MANDIR)/cat8/opcom.8
  168. X
  169. Xarchive: $(OPSOURCES)
  170. X    archive $(OPSOURCES)
  171. X
  172. Xrelease: $(OPSOURCES)
  173. X    modsource +1 $(CSOURCES)
  174. X    modsource +2 $(CSOURCES)
  175. X    modsource +1 -c $(HFILES)
  176. X    modsource +2 -c $(HFILES)
  177. X    modsource +1 -mk $(MAKEFILES) README
  178. X    modsource +2 -mk $(MAKEFILES) README
  179. X    modsource +1 - $(SHELLS)
  180. X    modsource +2 - $(SHELLS)
  181. X    archive $(OPSOURCES)
  182. X
  183. Xversion: $(OPSOURCES)
  184. X    modsource -1 $(CSOURCES)
  185. X    modsource -1 -c $(HFILES)
  186. X    modsource -1 -mk $(MAKEFILES) README
  187. X    modsource -1 - $(SHELLS)
  188. X    archive $(OPSOURCES)
  189. X
  190. Xshar:    $(SOURCES)
  191. X    rm -f Part?? Part??.Z
  192. X    makekit $(SUBDIRS) $(SOURCES) $(DIRENT)
  193. X
  194. Xclean:
  195. X    -rm -f *.BAK *.o opcom detab opcom.8 tmp.* sysdep.h \
  196. X    nohup.out core Part?? Part??.Z
  197. END_OF_bsd.make
  198. if test 1915 -ne `wc -c <bsd.make`; then
  199.     echo shar: \"bsd.make\" unpacked with wrong size!
  200. fi
  201. # end of overwriting check
  202. fi
  203. if test -f config -a "${1}" != "-c" ; then 
  204.   echo shar: Will not over-write existing file \"config\"
  205. else
  206. echo shar: Extracting \"config\" \(789 characters\)
  207. sed "s/^X//" >config <<'END_OF_config'
  208. X: use /bin/sh
  209. X
  210. X# opcom configuration script.
  211. X#
  212. X# In the first part of this script the directories and the administration
  213. X# for opcom are defined.
  214. X# Refer to all of these only by the environment variables defined here.
  215. X
  216. X#++
  217. X# AUTHOR(S)
  218. X#
  219. X#      C.G.S.M. Braam
  220. X#      Eindhoven University of Technology
  221. X#      Computing Centre
  222. X#      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  223. X# CREATION DATE
  224. X#    Thu Jan  5 11:09:45 MET 1989
  225. X# LAST MODIFICATION
  226. X#    Tue Jan 17 13:15:48 MET 1989
  227. X# VERSION/RELEASE
  228. X#    1.3
  229. X#--
  230. X
  231. X#    *** System dependent variables ***
  232. X
  233. XOPCOMDIR="/usr/local/lib/opcom"    
  234. XCOMMANDS="$OPCOMDIR/commands"        # command file
  235. XPROFILE="$OPCOMDIR/profile"        # profile
  236. X
  237. X#    *** End system dependent variables ***
  238. X
  239. Xsed 's%XCOMMANDS%'"$COMMANDS"'%g
  240. X     s%XPROFILE%'"$PROFILE"'%g' $*
  241. END_OF_config
  242. if test 789 -ne `wc -c <config`; then
  243.     echo shar: \"config\" unpacked with wrong size!
  244. fi
  245. chmod +x config
  246. # end of overwriting check
  247. fi
  248. if test -f detab.c -a "${1}" != "-c" ; then 
  249.   echo shar: Will not over-write existing file \"detab.c\"
  250. else
  251. echo shar: Extracting \"detab.c\" \(1053 characters\)
  252. sed "s/^X//" >detab.c <<'END_OF_detab.c'
  253. X/*++
  254. X/* NAME
  255. X/*    detab 1
  256. X/* SUMMARY
  257. X/*    expand tabs to blanks
  258. X/* PROJECT
  259. X/*    documentation
  260. X/* SYNOPSIS
  261. X/*    detab
  262. X/* DESCRIPTION
  263. X/*    Detab is a filter that expands tab stops in its standard input
  264. X/*    to blanks. A tab stop distance of eight blanks is assumed.
  265. X/* BUGS
  266. X/*    This program does not handle backspaces.
  267. X/* AUTHOR(S)
  268. X/*    Wietse Venema
  269. X/*    Eindhoven University of Technology
  270. X/*    Department of Mathematics and Computer Science
  271. X/*    Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  272. X/* CREATION DATE
  273. X/*    Sep 14 1985
  274. X/* LAST MODIFICATION
  275. X/*    Mon May  4 20:32:48 GMT+1:00 1987
  276. X/* VERSION/RELEASE
  277. X/*    1.3
  278. X/*--*/
  279. X
  280. X#include <stdio.h>
  281. X
  282. X#define BLANK    ' '
  283. X
  284. Xmain()
  285. X{
  286. X    register int c;        /* character buffer */
  287. X    register int ccount = 0;    /* nr of characters printed on current line */
  288. X
  289. X    while ((c = getchar()) != EOF) {
  290. X    switch (c) {
  291. X
  292. X        case '\r':
  293. X        case '\n':  putchar(c);
  294. X            ccount = 0;
  295. X            break;
  296. X
  297. X        case '\t':  do { putchar(BLANK); } while (++ccount & 7);
  298. X            break;
  299. X
  300. X        default:    putchar(c);
  301. X            ccount++;
  302. X            break;
  303. X    }
  304. X    }
  305. X    exit(0);
  306. X}
  307. END_OF_detab.c
  308. if test 1053 -ne `wc -c <detab.c`; then
  309.     echo shar: \"detab.c\" unpacked with wrong size!
  310. fi
  311. # end of overwriting check
  312. fi
  313. if test -f opcom.c -a "${1}" != "-c" ; then 
  314.   echo shar: Will not over-write existing file \"opcom.c\"
  315. else
  316. echo shar: Extracting \"opcom.c\" \(9468 characters\)
  317. sed "s/^X//" >opcom.c <<'END_OF_opcom.c'
  318. X/*++
  319. X/* NAME
  320. X/*      opcom 8
  321. X/* SUMMARY
  322. X/*      execute an operator command.
  323. X/* SYNOPSIS
  324. X/*    .fi
  325. X/*    .B opcom 
  326. X/*     command [ arguments ]
  327. X/* DESCRIPTION
  328. X/*    .I Opcom
  329. X/*    enables users belonging to a special group (as defined in /etc/group)
  330. X/*    to execute a limited set of commands with another userid (e.g. root)
  331. X/*    or groupid. The file
  332. X/*    .I XCOMMANDS
  333. X/*    describes which commands are allowed for which groups and which
  334. X/*    userid (groupid) must be used.
  335. X/*    .br
  336. X/*    .I Command
  337. X/*    is a valid operator command, if it matches an entry in
  338. X/*    .I XCOMMANDS.
  339. X/*    Those entries have the following form:
  340. X/*    
  341. X/*    path-name : operator-group : [ new-userid ] [ : [ new-groupid ]]
  342. X/*    
  343. X/*    .I Command
  344. X/*    matches an entry, if it is the basename of 
  345. X/*    .I path-name
  346. X/*    and if the user executing
  347. X/*    .I opcom
  348. X/*    is a member of the group
  349. X/*    .I operator-group
  350. X/*    (as defined in /etc/group).
  351. X/*    If
  352. X/*    .I command
  353. X/*    matches more than one entry, the first matching entry is selected.
  354. X/*    This allows multiple levels of privilege.
  355. X/*    .br
  356. X/*    If no match is found,
  357. X/*    .I opcom
  358. X/*    aborts with the message "access denied.".
  359. X/*
  360. X/*    .I Command
  361. X/*    is executed with the given
  362. X/*    .I arguments.
  363. X/*    The environment is the current environment with the following
  364. X/*    exceptions:
  365. X/*    .br
  366. X/*    If
  367. X/*    .I user-id (group-id)
  368. X/*    is not empty, the effective and real userid (groupid) are set to
  369. X/*    .I user-id (group-id).
  370. X/*    .br
  371. X/*    If
  372. X/*    .I user-id (group-id)
  373. X/*    is empty, the effective and real userid (groupid)
  374. X/*    are set to the real userid (groupid).
  375. X/*
  376. X/*    The following environment variables are set:
  377. X/*    .IP \- 2.4
  378. X/*    COMMAND to
  379. X/*    .I command.
  380. X/*    .IP \-
  381. X/*    GROUP to
  382. X/*    .I operator-group.
  383. X/*    .IP \-
  384. X/*    IFS to blank, tab and new line.
  385. X/*    .IP \-
  386. X/*    ORGUSER to the login name of the real userid of the invoker of
  387. X/*    .I opcom.
  388. X/*    .IP \-
  389. X/*    PATH to /
  390. X/*    .IP \-
  391. X/*    USER and LOGNAME to the login name of the real userid executing
  392. X/*    .I command.
  393. X/*    .RE
  394. X/*
  395. X/*    If the script 
  396. X/*    .I XPROFILE
  397. X/*    exists, this script will be executed
  398. X/*    within the shell, that executes
  399. X/*    .I command.
  400. X/*    So changes to the environment (e.g. PATH) can be put there.
  401. X/* FILES
  402. X/*    XCOMMANDS
  403. X/*    XPROFILE
  404. X/*    /etc/group
  405. X/* CAVEAT
  406. X/*    Beware of Trojan horses: don't allow commands with shell escapes.
  407. X/* BUGS
  408. X/*    The syntax of entries in
  409. X/*    .I XCOMMANDS
  410. X/*    is not checked rigorously.
  411. X/* DIAGNOSTICS
  412. X/*    In case of error
  413. X/*    .I opcom
  414. X/*    prints an error message on standard error and terminates
  415. X/*    with nonzero status.
  416. X/* AUTHOR(S)
  417. X/*
  418. X/*      C.G.S.M. Braam
  419. X/*      Eindhoven University of Technology
  420. X/*      Computing Centre
  421. X/*      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  422. X/* BUG REPORTS TO
  423. X/*    rccarel@eutrc3.UUCP
  424. X/* CREATION DATE
  425. X/*    Wed Jan  4 14:12:59 MET 1989
  426. X/* LAST MODIFICATION
  427. X/*    Tue Jan 17 13:15:08 MET 1989
  428. X/* VERSION/RELEASE
  429. X/*    1.3
  430. X/*--*/
  431. X
  432. X#include <stdio.h>
  433. X#include "sysdep.h"
  434. X#include <grp.h>
  435. X#include <pwd.h>
  436. X#include <sys/types.h>
  437. X#include <sys/stat.h>
  438. X#include <varargs.h>
  439. X#include <ctype.h>
  440. X
  441. Xextern void exit ();
  442. Xextern void perror ();
  443. X
  444. Xextern int errno;
  445. Xextern char *sys_errlist [];
  446. Xextern int sys_nerr;
  447. X
  448. Xextern int geteuid ();
  449. Xextern int getgid ();
  450. Xextern int setuid ();
  451. Xextern struct group *getgrnam ();
  452. Xextern struct passwd *getpwnam ();
  453. Xextern struct passwd *getpwuid ();
  454. Xextern char *malloc ();
  455. Xextern int putenv ();
  456. Xextern int system ();
  457. X
  458. X#define WARN    0
  459. X#define ABORT    1
  460. X
  461. Xstruct command {
  462. X    char *name;
  463. X    char path [1024];
  464. X    char group [32];
  465. X    char new_group [32];
  466. X    char new_user [32];
  467. X};
  468. X
  469. Xvoid PERROR ();
  470. Xint check_group ();
  471. Xvoid error ();
  472. Xvoid exec_cmnd ();
  473. Xstruct command *get_command ();
  474. Xchar *nextitem ();
  475. Xvoid usage_error ();
  476. Xvoid set_env ();
  477. Xvoid set_ids ();
  478. X
  479. Xchar orguser [32];
  480. Xchar *progname;                /* used for diagnostics */
  481. X
  482. Xmain (argc, argv)
  483. Xint argc;
  484. Xchar **argv;
  485. X{
  486. X    int fd;
  487. X    struct command *command;
  488. X
  489. X    /* close all file descriptors > 2 */
  490. X    for (fd = 3; fd <= _NFILE; fd++)
  491. X    (void) close (fd);
  492. X    if (progname = strrchr (*argv, '/'))
  493. X    progname++;
  494. X    else
  495. X    progname = *argv;
  496. X    argv++; argc--;
  497. X
  498. X    if (argc == 0)
  499. X    usage_error ();
  500. X
  501. X    command = get_command (*argv);
  502. X    set_ids (command->new_user, command->new_group);
  503. X    exec_cmnd (command, argc-1, argv+1);
  504. X    return (0);    /* makes lint happy    */
  505. X}
  506. X
  507. Xstruct command *get_command (name)
  508. Xchar *name;
  509. X{
  510. X    static char cmndbuf [BUFSIZ];
  511. X    static struct command command;
  512. X    int found = 0;
  513. X    char ch,
  514. X     *cmnd,
  515. X     *pc,
  516. X     *ptail,
  517. X     *pt;
  518. X    FILE *file;
  519. X
  520. X    if ((file = fopen (COMMANDS, "r")) == NULL)
  521. X    error (ABORT, "cannot open %s for reading.", COMMANDS);
  522. X    command.name = name;
  523. X    while (fgets (cmndbuf, BUFSIZ, file) != NULL) {
  524. X    for (cmnd = cmndbuf; isspace (*cmnd); cmnd++);
  525. X    pt = command.path;
  526. X    ptail = cmnd;
  527. X    while (! (isspace (ch = *ptail) || (ch == ':') || (ch == 0))) {
  528. X        *pt++ = ch;
  529. X        ptail++;
  530. X    }
  531. X    *pt = 0;
  532. X    while (isspace (*ptail))
  533. X        ptail++;
  534. X    if (*ptail != ':')    /* invalid entry    */
  535. X        continue;
  536. X    pt = command.path;
  537. X    if ((pc = strrchr (pt, '/')) == NULL)
  538. X        pc = pt;
  539. X    else
  540. X        pc++;
  541. X    if (strcmp (name, pc) == 0) {
  542. X        ptail = nextitem (ptail+1, command.group);
  543. X        if ((found = check_group (command.group)))
  544. X        break;
  545. X    }
  546. X    }
  547. X    if (! found)
  548. X    error (ABORT, "access denied.");
  549. X    (void) fclose (file);
  550. X    ptail = nextitem (ptail, command.new_user);
  551. X    ptail = nextitem (ptail, command.new_group);
  552. X    return (&command);
  553. X}
  554. X
  555. Xchar *nextitem (pstart, target)
  556. Xchar *pstart,
  557. X     *target;
  558. X{
  559. X    char ch,
  560. X     *ps = pstart,
  561. X     *pt = target;
  562. X
  563. X     while (isspace (*ps)) ps++;
  564. X     if (*ps == 0) {
  565. X        *pt = 0;
  566. X        return (ps);
  567. X    }
  568. X    for (ch = *ps; (ch != ':') & (ch != 0); ch = *++ps)
  569. X        *pt++ = ch;
  570. X    *pt-- = 0;
  571. X    for (ch = *pt; isspace (ch); ch = *pt--)
  572. X        *pt = 0;
  573. X    if (*ps == 0)
  574. X        return (ps);
  575. X    else
  576. X        return (ps+1);
  577. X}
  578. X
  579. Xint check_group (groupname)
  580. Xchar *groupname;
  581. X{
  582. X    int found = 0;
  583. X    char **gr_list;
  584. X    struct group *group;
  585. X    struct passwd *passwd;
  586. X
  587. X    if ((passwd = getpwuid (getuid ())) == NULL)
  588. X    error (ABORT, "cannot find passwd entry for userid %d.", getuid ());
  589. X    (void) strcpy (orguser, passwd->pw_name);
  590. X    if ((group = getgrnam (groupname)) != NULL)
  591. X    for (gr_list = group->gr_mem; *gr_list != NULL; gr_list++) {
  592. X        if ((found = (strcmp (orguser, *gr_list) == 0)))
  593. X        break;
  594. X    }
  595. X    return (found);
  596. X}
  597. X
  598. Xvoid set_ids (new_user, new_group)
  599. Xchar *new_user,
  600. X     *new_group;
  601. X{
  602. X    struct group *group;
  603. X    struct passwd *passwd;
  604. X
  605. X    if (*new_group != 0) {
  606. X    /* not empty, must be set before uid is set     */
  607. X    if ((group = getgrnam (new_group)) == NULL)
  608. X        error (ABORT, "cannot find group entry for groupid %s.", new_group);
  609. X    if (setgid (group->gr_gid) < 0)
  610. X        PERROR (ABORT);
  611. X    }
  612. X    if (*new_user != 0) {    /* not empty     */
  613. X    if ((passwd = getpwnam (new_user)) == NULL)
  614. X        error (ABORT, "cannot find passwd entry for userid %s.", new_user);
  615. X    if (setuid (passwd->pw_uid) < 0)
  616. X        PERROR (ABORT);
  617. X    } else if (setuid (getuid ()) < 0)
  618. X    PERROR (ABORT);
  619. X}
  620. X
  621. Xvoid exec_cmnd (command, argc, argv)
  622. Xstruct command *command;
  623. Xint argc;
  624. Xchar **argv;
  625. X{
  626. X    unsigned cmnd_size = 0;
  627. X    int i,
  628. X    rslt;
  629. X    struct stat prstat;
  630. X    char 
  631. X     *cmnd,
  632. X     *pa,
  633. X     *pc;
  634. X
  635. X    set_env (command->name, command->group, command->new_user);
  636. X    cmnd_size = strlen (command->path)+32;
  637. X    for (i = 0; i < argc; i++)
  638. X    cmnd_size += strlen (argv [i])+1;
  639. X    pc = cmnd = malloc (cmnd_size+strlen (PROFILE));
  640. X    if ((stat (PROFILE, &prstat) == 0) && (prstat.st_mode & 0400)) {
  641. X    /* We must execute the profile */
  642. X    (void) sprintf (pc, ". %s;", PROFILE);
  643. X    pc += strlen (pc);
  644. X    }
  645. X    pa = command->path;
  646. X    while (*pa != 0)
  647. X    *pc++ = *pa++;
  648. X    *pc++ = ' ';
  649. X    while (argc-- > 0) {
  650. X    pa = *argv++;
  651. X    while (*pa != 0)
  652. X        *pc++ = *pa++;
  653. X    *pc++ = ' ';
  654. X    }
  655. X    *pc = 0;    /* close string    */
  656. X
  657. X    if ((rslt = system (cmnd)) < 0)
  658. X    PERROR (ABORT);
  659. X    exit (rslt);
  660. X}
  661. X
  662. Xvoid set_env (name, group, new_user)
  663. Xchar *name,
  664. X     *group,
  665. X     *new_user;
  666. X{
  667. X#define PUTENV(e)    { if (putenv (e) < 0) PERROR (ABORT); }
  668. X    static char envbuf [512];
  669. X    char *penv = envbuf;
  670. X
  671. X    PUTENV ("IFS= \t\n");
  672. X    PUTENV ("PATH=/");
  673. X    (void) sprintf (penv, "ORGUSER=%s", orguser);
  674. X    PUTENV (penv);
  675. X    penv += strlen (penv)+1;
  676. X    (void) sprintf (penv, "COMMAND=%s", name);
  677. X    PUTENV (penv);
  678. X    penv += strlen (penv)+1;
  679. X    (void) sprintf (penv, "GROUP=%s", group);
  680. X    PUTENV (penv);
  681. X    penv += strlen (penv)+1;
  682. X    if (*new_user == 0) {
  683. X    (void) sprintf (penv, "USER=%s", orguser);
  684. X    PUTENV (penv);
  685. X    penv += strlen (penv)+1;
  686. X    (void) sprintf (penv, "LOGNAME=%s", orguser);
  687. X    PUTENV (penv);
  688. X    } else {
  689. X    (void) sprintf (penv, "USER=%s", new_user);
  690. X    PUTENV (penv);
  691. X    penv += strlen (penv)+1;
  692. X    (void) sprintf (penv, "LOGNAME=%s", new_user);
  693. X    PUTENV (penv);
  694. X    }
  695. X}
  696. X
  697. Xvoid PERROR (why)
  698. Xint why;
  699. X{
  700. X    perror (progname);
  701. X    if (why == ABORT)
  702. X    exit (1);
  703. X}
  704. X
  705. Xvoid usage_error ()
  706. X{
  707. X    error (ABORT, "usage: %s command [ arguments ]", progname);
  708. X}
  709. X
  710. X/* error - barf and quit */
  711. X
  712. X/* VARARGS1 */
  713. X
  714. Xvoid error (why, fmt, va_alist)
  715. Xint why;
  716. Xregister char *fmt;
  717. Xva_dcl
  718. X{
  719. X    va_list s;
  720. X
  721. X    va_start(s);
  722. X
  723. X    (void) fprintf (stderr, "%s: ", progname);
  724. X    for (/* void */; *fmt; fmt++) {
  725. X    if (*fmt != '%') {
  726. X        (void) putc(*fmt,stderr);
  727. X    } else if (*++fmt == 's') {
  728. X        (void) fputs(va_arg(s,char *),stderr);
  729. X    } else if (*fmt == 'c') {
  730. X        (void) putc(va_arg(s,int),stderr);
  731. X    } else if (*fmt == 'u') {
  732. X        (void) fprintf(stderr,"%u",va_arg(s,unsigned));
  733. X    } else if (*fmt == 'd') {
  734. X        (void) fprintf(stderr,"%d",va_arg(s,int));
  735. X    }
  736. X    }
  737. X    va_end(s);
  738. X    (void) fprintf (stderr, "\n");
  739. X    if (why != WARN)
  740. X    exit (why);
  741. X    (void) fflush (stderr);
  742. X}
  743. END_OF_opcom.c
  744. if test 9468 -ne `wc -c <opcom.c`; then
  745.     echo shar: \"opcom.c\" unpacked with wrong size!
  746. fi
  747. # end of overwriting check
  748. fi
  749. if test -f srctoman -a "${1}" != "-c" ; then 
  750.   echo shar: Will not over-write existing file \"srctoman\"
  751. else
  752. echo shar: Extracting \"srctoman\" \(4670 characters\)
  753. sed "s/^X//" >srctoman <<'END_OF_srctoman'
  754. X: srctoman - see comment below
  755. X
  756. X: process arguments
  757. X
  758. XLOCAL=
  759. XHOST=
  760. Xwhile :
  761. Xdo
  762. X    case $1 in
  763. X    -L) HOST=`uuname -l | tr "[a-z]" "[A-Z]"`
  764. X    LOCAL=LOCAL;;
  765. X [0-9]) SECT=$1;;
  766. X     -) LANG=$1; B='[#:]';;
  767. X  -awk) LANG=$1; B='#';;
  768. X    -c) LANG=$1; B='\/\*';;
  769. X    -f) LANG=$1; B='[Cc]';;
  770. X   -mk) LANG=$1; B='#';;
  771. X -n|-t) LANG=$1; B='\\"';;
  772. X    -p) LANG=$1; B='{';;
  773. X    -r) LANG=$1; B='#';;
  774. X    -C) LANG=$1; B=$2; shift;;
  775. X    -*) ERROR="unknown option: $1"; break;;
  776. X    "") ERROR="missing file argument"; break;;
  777. X     *) break;;
  778. X    esac
  779. X    shift
  780. Xdone
  781. X
  782. X: check error status
  783. X
  784. Xcase $ERROR in
  785. X"") ;;
  786. X *) echo "$0: $ERROR" 1>&2
  787. X    echo "usage: $0 [-|-awk|-c|-f|-mk|-n|-p|-t|-r] [section] file(s)" 1>&2; exit 1;;
  788. Xesac
  789. X
  790. X: set up for file suffix processing
  791. X
  792. Xcase $LANG in
  793. X"") sh='[:#]';    r='#';    rh=$r;    awk='#'; mk='#';
  794. X    c='\/\*';    h=$c;    y=$c;    l=$c;
  795. X    f='[Cc]';    fh=$f;    p='{';    ph=$p;
  796. X    ms='\\"';    nr=$ms;    mn=$ms;    man=$ms;
  797. Xesac
  798. X
  799. X: extract comments
  800. X
  801. Xfor i in $*
  802. Xdo
  803. X    case $LANG in
  804. X    "") eval B\="\$`expr $i : '^.*\.\([^.]*\)$'`"
  805. X    test "$B" || { echo "$0: unknown suffix: $i; assuming c" 1>&2; B=$c; }
  806. X    esac
  807. X    sed '
  808. X    /^'"$B"'++/,/^'"$B"'--/!d
  809. X    /^'"$B"'++/d
  810. X    /^'"$B"'--/d
  811. X    s/[     ]*$//
  812. X    /^'"$B"' \([A-Z]\)/{
  813. X    s//\1/
  814. X    /^NAME/{
  815. X        N
  816. X        s/^.*\n'"$B"'[     ]*//
  817. X        h
  818. X        y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
  819. X        s/,.*\([     ][0-9][     ]*\)$/ \1/
  820. X        s/^.*$/.TH & '"$SECT $LOCAL $HOST"'\
  821. X.ad\
  822. X.fi\
  823. X.SH NAME/
  824. X        p
  825. X        g
  826. X        s/[     ][0-9][     ]*$//
  827. X        a\
  828. X\\-
  829. X        p
  830. X        d
  831. X    }
  832. X    /^SUMMARY/d
  833. X    /^DESCRIPTION/s//.SH &\
  834. X.ad\
  835. X.fi/
  836. X    /^BUGS/s//.SH &\
  837. X.ad\
  838. X.fi/
  839. X    /^DIAGNOSTICS/s//.SH &\
  840. X.ad\
  841. X.fi/
  842. X    /^[A-Z][A-Z][A-Z][^a-z]*$/s//.SH &\
  843. X.na\
  844. X.nf/
  845. X    p
  846. X    d
  847. X    }
  848. X    s/^'"$B"'[     ]*//
  849. X    s/^[     ]*$//
  850. X' $i
  851. Xdone | ./detab
  852. X
  853. Xexit
  854. X
  855. X:++
  856. X: NAME
  857. X:    srctoman 1
  858. X: SUMMARY
  859. X:    extract manual page from source file comment
  860. X: PACKAGE
  861. X:    source file maintentance tools
  862. X: SYNOPSIS
  863. X:    srctoman [-|-awk|-c|-f|-mk|-m|-n|-p|-t|-r] [section] file(s)
  864. X: DESCRIPTION
  865. X:    Sourcetoman converts comments in various programming languages to
  866. X:    UNIX-style manual pages.
  867. X:    The command processes comments in the style of newsource(1);
  868. X:    its standard output is suitable for formatting with nroff(1) or 
  869. X:    troff(1) using the "-man" macro package.  
  870. X:    Typically, srctoman is integrated with make(1) scripts.
  871. X:    If the option -L is given the text <hostname> (LOCAL) will be in
  872. X:    the heading.
  873. X:
  874. X:    Source files are processed in the indicated order; if no
  875. X:    files argument the command produces no output.
  876. X:
  877. X:    The source file language can be specified through a command-line
  878. X:    option, or can be implied by the filename suffix.
  879. X:    The expected start-of-comment symbol is shown in the last column.
  880. X:
  881. X: .nf
  882. X    option    language    comment
  883. X
  884. X    -    shell        [:#]
  885. X    -awk    awk        #
  886. X    -c    c        /*
  887. X    -f    fortran        [Cc]
  888. X    -mk    make        #
  889. X    -n    nroff        \\"
  890. X    -p    pascal        {
  891. X    -t    troff        \\"
  892. X    -r    ratfor        #
  893. X    -C    any language    next argument
  894. X: .fi
  895. X:
  896. X: .nf
  897. X    suffix    language    comment
  898. X
  899. X    .awk    awk        #
  900. X    .c    c        /*
  901. X    .f    fortran        [Cc]
  902. X    .fh    fortran        [Cc]
  903. X    .h    c        /*
  904. X    .l    lex        /*
  905. X    .man    nroff,troff    \\"
  906. X    .mk    make        #
  907. X    .me    nroff,troff    \\"
  908. X    .ms    nroff,troff    \\"
  909. X    .nr    nroff,troff    \\"
  910. X    .p    pascal        {
  911. X    .ph    pascal        {
  912. X    .r    ratfor        #
  913. X    .rh    ratfor        #
  914. X    .sh    shell        [:#]
  915. X    .y    yacc        /*
  916. X: .fi
  917. X:
  918. X:    The required format of comments is discussed below, where SOC
  919. X:    stands for the start-of-comment symbol of the language being used.
  920. X:
  921. X:    1) Start of manual: SOC, followed by `++'.
  922. X:
  923. X:    2) Section heading: SOC, blank, section name in upper case.
  924. X:
  925. X:    3) New paragraph: empty line or line with SOC only.
  926. X:
  927. X:    4) All other text: SOC and subsequent blanks or tabs are removed.
  928. X:    Lines that do not start with SOC are left unchanged (useful for 
  929. X:    inclusion of program text).
  930. X:
  931. X:    5) End of manual: SOC, followed by `--'.
  932. X:    An end-of-comment may follow if the source file language requires this.
  933. X:
  934. X:    The following manual sections receive a special treatment:
  935. X:    NAME and SUMMARY should appear at the beginning and in
  936. X:    this order; DESCRIPTION, DIAGNOSTICS and BUGS will be
  937. X:    right-margin adjusted.
  938. X:    Other sections may be added freely without confusing srctoman.
  939. X: COMMANDS
  940. X:    sh(1), sed(1), detab(1)
  941. X: SEE ALSO
  942. X:    newsource(1), modsource(1), xman(1)
  943. X:    The earlier commands new(1), mod(1), mkman(1) and dssman(1)
  944. X:    by Ruud Zwart and Ben Noordzij (Erasmus University, Rotterdam) 
  945. X: DIAGNOSTICS
  946. X:    The program complaints if an unknown language is specified
  947. X:    of if the language cannot be deduced from the file suffix.
  948. X: AUTHOR(S)
  949. X:    W.Z. Venema
  950. X:    Eindhoven University of Technology
  951. X:    Department of Mathematics and Computer Science
  952. X:    Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  953. X: CREATION DATE
  954. X:    Fri Jan 17 22:59:27 MET 1986
  955. X: LAST MODIFICATION
  956. X:    Tue Mar 22 07:24:47 PST 1988
  957. X: VERSION/RELEASE
  958. X:    1.20
  959. X:--
  960. X
  961. X
  962. END_OF_srctoman
  963. if test 4670 -ne `wc -c <srctoman`; then
  964.     echo shar: \"srctoman\" unpacked with wrong size!
  965. fi
  966. chmod +x srctoman
  967. # end of overwriting check
  968. fi
  969. if test -f sysdep -a "${1}" != "-c" ; then 
  970.   echo shar: Will not over-write existing file \"sysdep\"
  971. else
  972. echo shar: Extracting \"sysdep\" \(272 characters\)
  973. sed "s/^X//" >sysdep <<'END_OF_sysdep'
  974. X#ifndef _NFILE
  975. X#include <sys/param.h>
  976. X#define _NFILE    NOFILE
  977. X#endif
  978. X
  979. X#ifdef SYSV
  980. X#define SIII
  981. X#include <string.h>
  982. X#else
  983. X#include <strings.h>
  984. X#define strchr    index
  985. X#define strrchr    rindex
  986. Xextern char *ctime ();
  987. X#endif
  988. X
  989. X#define COMMANDS    "XCOMMANDS"
  990. X#define PROFILE        "XPROFILE"
  991. END_OF_sysdep
  992. if test 272 -ne `wc -c <sysdep`; then
  993.     echo shar: \"sysdep\" unpacked with wrong size!
  994. fi
  995. # end of overwriting check
  996. fi
  997. if test -f sysv.make -a "${1}" != "-c" ; then 
  998.   echo shar: Will not over-write existing file \"sysv.make\"
  999. else
  1000. echo shar: Extracting \"sysv.make\" \(1921 characters\)
  1001. sed "s/^X//" >sysv.make <<'END_OF_sysv.make'
  1002. X#++
  1003. X# NAME
  1004. X#    sysv.make 
  1005. X# SUMMARY
  1006. X#    makefile for opcom.
  1007. X# AUTHOR(S)
  1008. X#
  1009. X#      C.G.S.M. Braam
  1010. X#      Eindhoven University of Technology
  1011. X#      Computing Centre
  1012. X#      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  1013. X# CREATION DATE
  1014. X#    Thu Jan  5 10:41:57 MET 1989
  1015. X# LAST MODIFICATION
  1016. X#    Tue Jan 17 13:15:28 MET 1989
  1017. X# VERSION/RELEASE
  1018. X#    1.3
  1019. X#--
  1020. X
  1021. X# System dependent variables
  1022. X
  1023. XCC = cc
  1024. XCDEFS = -DSYSV
  1025. XCFLAGS = -O
  1026. XLFLAGS = -h -Ml
  1027. XBINDIR = /usr/local/bin
  1028. XMANDIR = /usr/local/man
  1029. X
  1030. X# End system dependent variables
  1031. X
  1032. XCSOURCES = opcom.c
  1033. XHFILES = sysdep
  1034. XSHELLS = config
  1035. XMAKEFILES = bsd.make sysv.make
  1036. XOPSOURCES = $(CSOURCES) $(HFILES) $(SHELLS) $(MAKEFILES) README
  1037. XUSOURCES = detab.c srctoman
  1038. XSOURCES = $(OPSOURCES) $(USOURCES)
  1039. X
  1040. Xall:    opcom
  1041. X
  1042. Xsysdep.h: sysdep config
  1043. X    sh config sysdep >sysdep.h
  1044. X
  1045. Xman:    opcom.8
  1046. X
  1047. Xopcom.8: opcom.c config detab
  1048. X    sh srctoman -L opcom.c | sh config >opcom.8
  1049. X
  1050. X# Lint.
  1051. X
  1052. Xlint:    sysdep.h
  1053. X    lint $(LFLAGS) $(CDEFS) opcom.c
  1054. X
  1055. X
  1056. Xdetab: detab.c
  1057. X    $(CC) $(CFLAGS) $(CDEFS) detab.c -o detab
  1058. X
  1059. Xopcom: opcom.c sysdep.h
  1060. X    $(CC) $(CFLAGS) $(CDEFS) opcom.c -o opcom
  1061. X
  1062. X# Installation and update.
  1063. X
  1064. Xinstall: opcom
  1065. X    cp opcom $(BINDIR)
  1066. X    cd $(BINDIR); chown root opcom; chmod u+s opcom
  1067. X
  1068. Xinstallman: man
  1069. X     cp opcom.8 $(MANDIR)/man8
  1070. X     rm -f $(MANDIR)/cat8/opcom.8
  1071. X
  1072. Xarchive: $(OPSOURCES)
  1073. X    archive $(OPSOURCES)
  1074. X
  1075. Xrelease: $(OPSOURCES)
  1076. X    modsource +1 $(CSOURCES)
  1077. X    modsource +2 $(CSOURCES)
  1078. X    modsource +1 -c $(HFILES)
  1079. X    modsource +2 -c $(HFILES)
  1080. X    modsource +1 -mk $(MAKEFILES) README
  1081. X    modsource +2 -mk $(MAKEFILES) README
  1082. X    modsource +1 - $(SHELLS)
  1083. X    modsource +2 - $(SHELLS)
  1084. X    archive $(OPSOURCES)
  1085. X
  1086. Xversion: $(OPSOURCES)
  1087. X    modsource -1 $(CSOURCES)
  1088. X    modsource -1 -c $(HFILES)
  1089. X    modsource -1 -mk $(MAKEFILES) README
  1090. X    modsource -1 - $(SHELLS)
  1091. X    archive $(OPSOURCES)
  1092. X
  1093. Xshar:    $(SOURCES)
  1094. X    rm -f Part?? Part??.Z
  1095. X    makekit $(SUBDIRS) $(SOURCES) $(DIRENT)
  1096. X
  1097. Xclean:
  1098. X    -rm -f *.BAK *.o opcom detab opcom.8 tmp.* sysdep.h \
  1099. X    nohup.out core Part?? Part??.Z
  1100. END_OF_sysv.make
  1101. if test 1921 -ne `wc -c <sysv.make`; then
  1102.     echo shar: \"sysv.make\" unpacked with wrong size!
  1103. fi
  1104. # end of overwriting check
  1105. fi
  1106. echo shar: End of archive 1 \(of 1\).
  1107. cp /dev/null ark1isdone
  1108. MISSING=""
  1109. for I in 1 ; do
  1110.     if test ! -f ark${I}isdone ; then
  1111.     MISSING="${MISSING} ${I}"
  1112.     fi
  1113. done
  1114. if test "${MISSING}" = "" ; then
  1115.     echo You have unpacked all 1 archives.
  1116.     rm -f ark[1-9]isdone
  1117. else
  1118.     echo You still need to unpack the following archives:
  1119.     echo "        " ${MISSING}
  1120. fi
  1121. ##  End of shell archive.
  1122. exit 0
  1123.  
  1124.